package nature.nano.control.script.parse;

import java.util.List;

import nature.nano.component.PrimaryPipe;
import nature.nano.component.SimpleProps;
import nature.nano.component.Strings;
import nature.nano.iface.Accepter;
import nature.nano.iface.Props;

public class ScriptLineParser extends PrimaryPipe {
	
	private Props rowProp;
	
	@Override
	public void anBegin(String type, Props props) {
		if (type.endsWith(Strings.row)) {
			rowProp = props;
		}
		slot(Strings.output).onBegin(type, props);
		slot(Strings.error).onBegin(type, props);
	}

	@Override
	public void anContent(String content) {
		Accepter accepter = slot(Strings.output);
		List<String> clazzs = StringHelper.split(content, Strings.rt);
		for (String clazz : clazzs) {
			// NOTE: Class[prop1=value1,prop2=value2](ObjectAlias).slot(SlotAlias)

			SimpleProps props = new SimpleProps();
			String propsString = extractProps(clazz);
			clazz = clazz.trim();
			String clazzString = clazz;
			if (propsString != null) {
				clazzString = clazz.replace(propsString, Strings.zeroString).trim();
			}
			
			clazzString = clazzString.replaceAll(Strings.regSpace, Strings.zeroString).trim();

			setClazzInfo(clazzString, props);

			accepter.onBegin(Strings.clazz, props);
			if (propsString != null) {
				parseProps(propsString.substring(1, propsString.length() - 1).trim(), accepter);				
			}
			accepter.onContent(clazz);
			accepter.onEnd(Strings.clazz);
		}
		accepter.onContent(content);
	}

	@Override
	public void anEnd(String type) {
		slot(Strings.output).onEnd(type);
		slot(Strings.error).onEnd(type);
	}
	
	private String extractProps(String clazz) {
		int lb = clazz.indexOf(Strings.lb);
		int rb = clazz.lastIndexOf(Strings.rb);

		if (lb > 0 && rb > lb) {
			String props = clazz.substring(lb, rb + 1).trim();
			if (props.length() == 0) {
				return null;
			}
			return props;
		}
		return null;
	}

	private void setClazzInfo(String clazzString, SimpleProps props) {
		int split = clazzString.lastIndexOf(Strings.period);
		if (split > 0) {
			setSlotInfo(clazzString.substring(split + 1, clazzString.length()), props);
			clazzString = clazzString.substring(0, split);
		}
		
		//props.add(Strings.origin, clazzString);
		
		String alias = extractAlias(clazzString);
		if (alias != null) {
			clazzString = clazzString.replace(alias, Strings.zeroString);
			props.add(Strings.clazzAlias, alias.substring(1, alias.length() - 1));
		}
		props.add(Strings.clazz, clazzString);
	}

	private void setSlotInfo(String slot, SimpleProps props) {
		String alias = extractAlias(slot);
		if (alias != null) {
			slot = slot.replace(alias, Strings.zeroString);
			props.add(Strings.slotAlias, alias.substring(1, alias.length() - 1));
		}
		props.add(Strings.slot, slot);
	}

	private void parseProps(String propsString, Accepter accepter) {
		if (propsString.indexOf(Strings.equal) <= 0) {
			parseAnonymousProp(propsString, accepter);
			return;
		}
		
		String[] pairs = propsString.split(Strings.comma);
		SimpleProps props = new SimpleProps();
		for (String pair : pairs) {
			List<String> prop = StringHelper.split(pair, Strings.equal);
			if (prop.size() == 2) {
				props.add(prop.get(0).trim(), prop.get(1).trim());
			} else {
				Accepter error = slot(Strings.error);
				SimpleProps eps = new SimpleProps(Strings.errorType, Strings.invalidKeyValueFormat, Strings.prop, pair);
				if (rowProp != null) {
					eps.add(Strings.row, rowProp.get(Strings.index));
				}
				error.onBegin(Strings.error, eps);
				error.onEnd(Strings.error);
			}
		}
		accepter.onBegin(Strings.props, props);
		accepter.onContent(propsString);
		accepter.onEnd(Strings.props);
	}

	private void parseAnonymousProp(String propsString, Accepter accepter) {
		String[] propsItem = propsString.split(Strings.comma);
		SimpleProps props = new SimpleProps();
		for (int i = 0; i < propsItem.length; ++i) {
			props.add(Strings.anonymous + i, propsItem[i].trim());
		}
		accepter.onBegin(Strings.props, props);
		accepter.onContent(propsString);
		accepter.onEnd(Strings.props);		
	}

	private String extractAlias(String string) {
		int lb = string.indexOf(Strings.lsb);
		int rb = string.lastIndexOf(Strings.rsb);

		if (lb > 0 && rb > lb) {
			String props = string.substring(lb, rb + 1).trim();
			if (props.length() == 0) {
				return null;
			}
			return props;
		}
		return null;
	}
	
}
